#include "DisplayGdi.h"
#include "Utils.h"
#include <atlimage.h>
#include <algorithm>
DisplayGdi::DisplayGdi()
{
    _render_type = 0;
    dx_ = 0;
    dy_ = 0;
    // 4*2^22=16*2^20=16MB
    //_image_data = new byte[MAX_IMAGE_WIDTH*MAX_IMAGE_WIDTH * 4];
}

DisplayGdi::~DisplayGdi()
{
    // SAFE_DELETE_ARRAY(_image_data);
}

long DisplayGdi::Bind(long hwnd, long render_type)
{
    if (!::IsWindow((HWND)hwnd))
        return 0;
    _hwnd = (HWND)hwnd;
    _render_type = render_type;

    if (render_type == RDT_NORMAL)
    {
        RECT rc, rc2;
        ::GetWindowRect(_hwnd, &rc);
        ::GetClientRect(_hwnd, &rc2);

        _width = rc2.right - rc2.left;
        _height = rc2.bottom - rc2.top;
        POINT pt = {0};
        ::ClientToScreen(_hwnd, &pt);
        dx_ = pt.x - rc.left;
        dy_ = pt.y - rc.top;
        _hdc = ::GetDC(NULL);
    }
    else
    { // client size
        RECT rc, rc2;
        ::GetWindowRect(_hwnd, &rc);
        ::GetClientRect(_hwnd, &rc2);
        _width = rc2.right - rc2.left;
        _height = rc2.bottom - rc2.top;
        POINT pt = {0};
        ::ClientToScreen(_hwnd, &pt);
        dx_ = pt.x - rc.left;
        dy_ = pt.y - rc.top;
        /*setlog("dx=%d dy=%d", dx_, dy_);*/
        if (_render_type == RDT_GDI)
        {
            _hdc = ::GetDC(_hwnd);
            // SetWindowLongA(topHwnd, GWL_EXSTYLE, dwExStyle | WS_EX_LAYERED);
            // UpdateWindow(topHwnd);
        }
        else if (RDT_GDI_DX2 == render_type)
        {
            _hdc = ::GetDC(_hwnd);
            _device_caps = GetDeviceCaps(_hdc, BITSPIXEL);
        }
        else
        {
            /*  HWND dx2TopHwnd = WinApi::GetTopWindowSp(_hwnd);
              GetPropA(dx2TopHwnd, "opstyle");
              long dx2ExStyle = GetWindowLongA(dx2TopHwnd, GWL_EXSTYLE);*/
            /*if (GetPropA(dx2TopHwnd, "opstyle_flag")) {
              dx2ExStyle = GetWindowLongA(dx2TopHwnd, GWL_EXSTYLE);
            } else {
              dx2ExStyle = GetWindowLongA(dx2TopHwnd, GWL_EXSTYLE);
              SetPropA(dx2TopHwnd, "opstyle", (HANDLE)dx2ExStyle);
              SetPropA(dx2TopHwnd, "opstyle_flag", (HANDLE)HANDLE_FLAG_INHERIT);
            }
          */
            /* SetWindowLongA(dx2TopHwnd, GWL_EXSTYLE, dx2ExStyle | WS_EX_LAYERED);
             UpdateWindow(dx2TopHwnd);*/
            _hdc = ::GetDC(_hwnd);
        }
    }

    if (_hdc == NULL)
    {
        setlog(L"hdc == NULL", _hdc);
        return 0;
    }

    // 创建一个与指定设备兼容的内存设备上下文环境
    _hmdc = CreateCompatibleDC(_hdc);
    if (_hmdc == NULL)
    {
        setlog(L"CreateCompatibleDC false");
        return -2;
    }

    // updata_screen();
    return 1;
}

long DisplayGdi::UnBind()
{
    // setlog("bkgdi::UnBindEx()");
    _hbmpscreen = (HBITMAP)SelectObject(_hmdc, _hbmp_old);
    // delete[dwLen_2]hDib;
    if (_hdc)
        DeleteDC(_hdc);
    _hdc = NULL;
    if (_hmdc)
        DeleteDC(_hmdc);
    _hmdc = NULL;

    if (_hbmpscreen)
        DeleteObject(_hbmpscreen);
    _hbmpscreen = NULL;
    // if (_hbmp_old)DeleteObject(_hbmp_old); _hbmp_old = NULL;
    return 1;
}

bool DisplayGdi::requestCapture(int x1, int y1, int w, int h, cv::Mat &img)
{
    // step 1.判断 窗口是否存在
    if (!::IsWindow(_hwnd))
        return 0;
    img.create(h, w, CV_8UC4);
    // img.create(w, h);
    if (_render_type == RDT_NORMAL)
    { // normal 拷贝的大小为实际需要的大小
        //
        /*	int w = rect.right - rect.left;
                int h = rect.bottom - rect.top;*/
        _hbmpscreen = CreateCompatibleBitmap(
            _hdc, w, h); // 创建与指定的设备环境相关的设备兼容的位图
        _hbmp_old = (HBITMAP)SelectObject(
            _hmdc, _hbmpscreen); // 选择一对象到指定的设备上下文环境中

        _bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        _bfh.bfSize = _bfh.bfOffBits + w * h * 4;
        _bfh.bfType = static_cast<WORD>(0x4d42);

        _bih.biBitCount = 32; // 每个像素字节大小
        _bih.biCompression = BI_RGB;
        _bih.biHeight = -h; // 高度
        _bih.biPlanes = 1;
        _bih.biSize = sizeof(BITMAPINFOHEADER);
        _bih.biSizeImage = w * h * 4; // 图像数据大小
        _bih.biWidth = w;             // 宽度

        // 对指定的源设备环境区域中的像素进行位块（bit_block）转换

        RECT rc;
        ::GetWindowRect(_hwnd, &rc);
        // setlog("rect left =%d top =%d, dx =%d, dy = %d", rc.left, rc.top, dx_,
        // dy_);
        int src_x = x1 + rc.left + dx_;
        int src_y = y1 + rc.top + dy_;
        if (BitBlt(_hmdc, 0, 0, w, h, _hdc, src_x, src_y, SRCCOPY))
        {
            // ok
        }
        else
        {
            setlog(L"error in bitbit");
        }

        GetDIBits(_hmdc, _hbmpscreen, 0L, (DWORD)h, img.data,
                  (LPBITMAPINFO)&_bih, (DWORD)DIB_RGB_COLORS);

        //_pmutex->unlock();
        if (_hbmpscreen)
            DeleteObject(_hbmpscreen);
        _hbmpscreen = NULL;
    }
    else if (RDT_GDI_DX2 == _render_type)
    {
        ATL::CImage image;
        image.Create(w, h, _device_caps);

        // 添加错误检查
        if (image.IsNull())
        {
            setlog(L"创建CImage失败");
            return false;
        }

        HDC hImageDC = image.GetDC();
        if (!BitBlt(hImageDC, 0, 0, w, h, _hdc, x1, y1, SRCCOPY))
        {
            setlog(L"BitBlt失败，错误码: %d", GetLastError());
            image.ReleaseDC();
            return false;
        }

        BYTE *pData = (BYTE *)image.GetBits();
        int pitch = image.GetPitch();

        // 计算有效字节数
        int valid_bytes = (std::min)(w * 4, abs(pitch));

        // 添加边界检查
        if (valid_bytes <= 0 || img.rows != h || img.cols != w)
        {
            setlog(L"无效的图像参数 w:%d h:%d pitch:%d", w, h, pitch);
            image.ReleaseDC();
            return false;
        }

        for (int y = 0; y < h; y++)
        {
            // 使用原始pitch值（可能为负）
            memcpy(img.ptr(y), pData + y * pitch, valid_bytes);
        }

        image.ReleaseDC();
    }
    else
    { // gdi ... 由于printwindow 函数的原因
        // 截取大小为实际的窗口大小，在后续的处理中，需要转化成客户区大小
        //
        RECT rc;
        ::GetWindowRect(_hwnd, &rc);
        int ww = rc.right - rc.left;
        int wh = rc.bottom - rc.top;

        // 修复1：创建正确尺寸的临时图像
        cv::Mat temp(wh, ww, CV_8UC4); // 高度在前，宽度在后

        GetDIBits(_hmdc, _hbmpscreen, 0L, (DWORD)wh, temp.data,
                  (LPBITMAPINFO)&_bih, (DWORD)DIB_RGB_COLORS);

        // 修复2：添加边界检查
        cv::Rect roi(
            (std::max)(0, x1 + dx_),
            (std::max)(0, y1 + dy_),
            (std::min)(w, temp.cols - (x1 + dx_)), // 宽度
            (std::min)(h, temp.rows - (y1 + dy_))  // 高度
        );

        if (roi.width > 0 && roi.height > 0)
        {
            temp(roi).copyTo(img);
        }
        else
        {
            setlog(L"无效的截图区域 x:%d y:%d w:%d h:%d", x1 + dx_, y1 + dy_, w, h);
            img = cv::Mat::zeros(h, w, CV_8UC4);
        }
        if (_hbmpscreen)
            DeleteObject(_hbmpscreen);
        _hbmpscreen = NULL;
    }
    return 1;
}
// void DisplayGdi::fmtFrameInfo(void *dst, HWND hwnd, int w, int h)
// {
//     m_frameInfo.hwnd = (unsigned __int64)hwnd;
//     m_frameInfo.frameId++;
//     m_frameInfo.time = ::GetTickCount64();
//     m_frameInfo.width = w;
//     m_frameInfo.height = h;
//     m_frameInfo.fmtChk();
//     memcpy(dst, &m_frameInfo, sizeof(m_frameInfo));
// }
